#include "ThreadPool.h"

ThreadPool::ThreadPool(int min, int max)
    : m_minThread(min), m_maxThread(max), m_stop(false), m_exitThreads(0) {
  //
  m_idleThreads = m_curThreads =
      max / 2;  // 闲置线程数和当前线程数初始化为最小值
  cout << "线程数量:" << m_curThreads << endl;
  // 创建管理者线程
  m_manager =
      new thread(&ThreadPool::manager, this);  // this表示属于当前类的实例
  //  创建工作线程
  for (int i = 0; i < m_maxThread / 2; ++i) {
    // 普通写法：先创建线程对象，再添加到线程列表，会发生数据拷贝
    // thread t = thread(&ThreadPool::worker, this);
    // m_workers.push_back(t);

    // 使用c++11创建线程对象，直接添加到线程列表，不会发生拷贝构造
    // m_workers.emplace_back(thread(&ThreadPool::worker, this));
    // emplace_back()需要在添加的过程中去构造对象才能避免拷贝和移动，
    // 也就是需要再函数的括号中去构造要添加的对象
    // 匿名对象，当把从线程队列中弹出（或者线程队列销毁）的时候销毁，不需要手动销毁

    // 更改为用map管理线程池
    thread t(&ThreadPool::worker, this);
    m_workers.insert(
        make_pair(t.get_id(), move(t)));  // 线程ID作为key，线程对象作为value
  }
}

ThreadPool::~ThreadPool() {
  // 通知管理者线程结束
  m_stop = true;
  // 唤醒所有堵塞在条件变量上的线程
  m_condition.notify_all();
  for (auto& it : m_workers) {  // 通过引用的方式取出线程对象，auto
                                // it取出的话会报错，线程不允许拷贝
    thread& t = it.second;

    // 判断线程是否可连接
    if (t.joinable()) {
      cout << "---------析构函数销毁线程ID:" << t.get_id() << "---------"
           << endl;
      t.join();  // 等待子线程结束
    }
  }

  // 判断管理者线程是否可连接
  if (m_manager->joinable()) {
    m_manager->join();  // 等待管理者线程结束
  }
  delete m_manager;  // 销毁管理者线程对象
}

void ThreadPool::addTask(function<void(void)> task) {
  {  // 使用大括号约束lock_guard的作用域
    // 管理互斥锁:
    // 当互斥锁打开状态时，lock进行加锁；当互斥锁关闭状态时，lock不进行加锁，堵在那里，直到互斥锁打开状态时才解锁
    lock_guard<mutex> lock(m_queueMutex);
    // 当lockd_guard对象离开作用域时，自动释放互斥锁
    m_tasks.emplace(task);  // 向任务队列中添加任务
  }
  //
  m_condition.notify_one();  // 唤醒管理者线程
}

void ThreadPool::manager(void) {
  while (!m_stop.load()) {
    // 检测当前线程数是否足够
    this_thread::sleep_for(chrono::seconds(1));  // 休眠3秒
    int idel = m_idleThreads.load();             // 闲置线程数
    int cur = m_curThreads.load();               // 当前线程数
    // 当空闲线程数大于当前线程数的2倍，且当前线程数大于最小线程数时，销毁线程
    if (idel > cur / 2 && cur > m_minThread) {
      // 每次销毁两个线程
      m_exitThreads.store(2);
      m_condition.notify_all();  // 唤醒所有线程

      // 对m_ids加锁，避免多线程访问
      lock_guard<mutex> lock(m_idsMutex);

      // 遍历已经销毁的线程ID，将其从m_workers中删除
      for (auto id : m_ids) {
        auto it = m_workers.find(id);
        if (it != m_workers.end()) {  // 线程存在
          cout << "------管理者销毁线程ID:" << id << "------" << endl;
          (*it).second.join();  // 等待线程结束
          m_workers.erase(it);  // 从线程列表中删除线程
        }
      }
      m_ids.clear();  // 清空线程ID列表
    }

    // 当空闲线程数等于0，且当前线程数小于最大线程数时，创建线程
    else if (idel == 0 && cur < m_maxThread) {
      // m_workers.emplace_back(thread(&ThreadPool::worker, this));
      thread t(&ThreadPool::worker, this);
      m_workers.insert(make_pair(t.get_id(), move(t)));
      // 打印管理者增加新线程
      //   cout << "------管理者增加线程ID:" << t.get_id() << "------" << endl;
      // 打印当先线程数量
      cout << "管理者增加线程-----当先线程数量:" << m_curThreads << endl;
      // 当前线程与空闲数++
      m_curThreads++;
      m_idleThreads++;
    }
  }
}

void ThreadPool::worker(void) {
  while (!m_stop.load()) {
    function<void(void)> task = nullptr;
    {
      // 使用大括号约束lock_guard的作用域
      // 管理互斥锁:
      // 当互斥锁打开状态时，lock进行加锁；当互斥锁关闭状态时，lock不进行加锁，堵在那里，直到互斥锁打开状态时才解锁
      unique_lock<mutex> locker(m_queueMutex);
      // 当unique_lock对象离开作用域时，自动释放互斥锁
      while (m_tasks.empty() && !m_stop) {
        // 等待任务队列中有任务
        m_condition.wait(locker);
        if (m_exitThreads.load() > 0) {
          m_exitThreads--;
          m_idleThreads--;
          m_curThreads--;
          cout << "----------- 线程退出--------ID:" << this_thread::get_id()
               << endl;
          lock_guard<mutex> lock(m_idsMutex);  // 对m_ids加锁，避免多线程访问
          m_ids.emplace_back(this_thread::get_id());
          return;
        }
      }
      if (!m_tasks.empty()) {
        // 取出任务
        cout << "取出任务---" << endl;
        // task = m_tasks.front();   // 使用拷贝构造函数，增加数据拷贝
        task = move(m_tasks.front());  // 使用移动构造函数，减少数据拷贝
        m_tasks.pop();                 // 弹出任务
      }
    }

    // 执行任务
    if (task) {
      // 闲置线程数--
      m_idleThreads--;
      // 执行任务
      task();
      // 闲置线程数++
      m_idleThreads++;
    }
  }
}

void calc(int x, int y) {
  int z = x + y;
  cout << "z = " << z << endl;
  this_thread::sleep_for(chrono::seconds(2));  // 休眠1秒
}
int calcl(int x, int y) {
  int z = x + y;
  this_thread::sleep_for(chrono::seconds(2));  // 休眠1秒
  return z;
} 

int main() {
  // 创建线程池
  ThreadPool pool;
  for (int i = 0; i < 10; i++) {
    // 绑定器
    auto obj = bind(calc, i, i * 2);
    pool.addTask(obj);  // 添加任务
  }
  // 阻塞主线程，获取键盘输入
  getchar();

  return 0;
}
